home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir30
/
eerems11.zip
/
EER_CORE.C
next >
Wrap
C/C++ Source or Header
|
1994-10-23
|
47KB
|
1,065 lines
/* ***************************************************************
An AutoCAD ADS program to remove "extra entities"
This module contains the core function that actually removes
the entities. Although this is a long and somewhat complex function,
I have left it as one function in order to maintain maximum
execution speed.
Jon Fleming CIS 70334,2443 July 19, 1994
Public Domain; Please give me credit if you use this or any
significant portion of it
Revision history:
July 19, 1994 Version 1.0: Initial release
October 23, 1994 Version 1.1: Modified EER_CORE.C to handle negative line
endpoints properly, and to avoid checking for entities to remove when
no entities were selected in the "candidates for removal" selection set.
Modified EER_CORE.C and EEREM.H to include version number report when
DoEntityRemoval starts.
*********************************************************** */
#include <stdio.h>
#include <math.h>
#include <time.h>
#include "adslib.h"
#include "eerem.h"
/* Function prototypes */
void DoEntityRemoval(ads_name);
extern short ColorStrToNum (char *);
extern ads_real DistancePointToLine(ads_point, ads_point, ads_point);
extern ads_real TransformAngle(ads_real, ads_point, ads_point);
extern int AngleIsBetween (ads_real, ads_real, ads_real);
extern VertexData GetVertexData(ads_name);
extern void SecToHMS (float, long *, long *, float *);
/* The constant 2*pi */
extern ads_real TwoPi;
/* Indicators for whether to consider layer, linetype, and/or color */
extern int CheckLayer, CheckLType, CheckColor;
/* Tolerance within which numbers are considered equal (at least, that's
approximately what this is; see below for more detail) */
extern ads_real Tolerance;
/* At last! The function that actually _removes_ extra entities! */
void DoEntityRemoval(ads_name EntitiesToCheck) {
char CurrentEntityLayer[32], CurrentEntityLType[32];
char CandidateLayer[32], CandidateLType[32];
char CurrentEntityType[16], CandidateEntityType[16];
short CurrentEntityColor, CoordNum;
short MaxColor, MinColor;
short CurrentEntityFlag, CurrentEntityFit;
short CandidateFlag, CandidateFit;
long CurrentEntityNumber, CandidateNumber, PointsRemoved = 0L;
long LinesRemoved = 0L, ArcsRemoved = 0L, CirclesRemoved = 0L;
long PlinesRemoved = 0L, TotalRemoved, ReportIncrement;
long NumEntsToCheck, NumEntsSelected;
ads_name CurrentEntityName, CandidateName, DeletionCandidates;
ads_name CurrentEntityVertex, CandidateVertex;
ads_point CurrentEntityP1, CurrentEntityP2, CurrentEntityEVec;
ads_point CandidateP1, CandidateP2, CandidateEVec;
ads_point BrickCorner1, BrickCorner2, BrickCorner3, BrickCorner4;
ads_point TempPoint;
ads_real CurrentEntitySize1, CurrentEntitySize2;
ads_real CurrentEntityStartAng, CurrentEntityEndAng;
ads_real CandidateStartAng, CandidateEndAng, TempStartAng, TempEndAng;
ads_real CandidateStartWidth, CandidateEndWidth;
ads_real TempReal, CurrentDistance;
VertexData CandidateVertexData, CurrentEntityVertexData;
struct resbuf *CurrentEAL, *CurrentEALItem, *CandidateEAL;
struct resbuf *CandidateEALItem, *SelSetCriteria;
struct resbuf SysVarResBuf, ECSResBuf1, ECSResBuf2;
clock_t StartTime, EndTime;
float TotalSeconds, ElapsedSeconds, EntitiesPerSecond;
long ElapsedHours, ElapsedMinutes;
int DecimalPlaces, Synchronized, ReachedLastVertex;
TwoPi = 2.0*acos(-1.0);
StartTime = clock();
ads_printf("\nExtra Entity Removal version %s", EEREM_VER);
/* End any undo group and start a new one */
ads_command(RTSTR, "._UNDO", RTSTR, "_GROUP", RTNONE);
/* Find out how many entities we have to check */
if (ads_sslength(EntitiesToCheck, &NumEntsToCheck) != RTNORM) {
NumEntsToCheck = 0L;
}
ads_printf("\nChecking %lu entities", NumEntsToCheck);
/* Determine an increment at which we will report progress to the user */
if (NumEntsToCheck <= REPORTTHRESHHOLD) {
ReportIncrement = NumEntsToCheck;
}
else if (NumEntsToCheck > 100*REPORTTHRESHHOLD) {
ReportIncrement = NumEntsToCheck/100;
}
else {
ReportIncrement = REPORTTHRESHHOLD;
}
ads_printf("\n");
/* Loop over all entities in the selection set */
for (CurrentEntityNumber = 0L; CurrentEntityNumber < NumEntsToCheck; CurrentEntityNumber++) {
/* Check for the user cancelling at a point at which we don't have any
memory allocated that we have to worry about freeing */
if (ads_usrbrk()) {
ads_printf("\n**Cancel**\n");
return;
}
/* Get the address of the Entity Association List of the current entity */
ads_ssname(EntitiesToCheck, CurrentEntityNumber, CurrentEntityName);
/* Check that we haven't already deleted this entity */
if ((CurrentEAL = CurrentEALItem = ads_entget(CurrentEntityName)) != NULL) {
/* Set up default values for items which may not be in the EAL of the
current entity */
CurrentEntityColor = 256;
strcpy(CurrentEntityLType, "BYLAYER");
CurrentEntityFlag = CurrentEntityFit = 0;
CurrentEntityEVec[X] = 0.0;
CurrentEntityEVec[Y] = 0.0;
CurrentEntityEVec[Z] = 1.0;
CurrentEntitySize1 = 0.0;
CurrentEntitySize2 = 0.0;
/* Extract the type, layer, color, linetype and any defining
points, radius, start and end angle, and extrusion vector of
the current entity */
while (CurrentEALItem != NULL) {
switch (CurrentEALItem->restype) {
case 0: {
strcpy(CurrentEntityType, CurrentEALItem->resval.rstring);
break;
}
case 6: {
strcpy(CurrentEntityLType, CurrentEALItem->resval.rstring);
break;
}
case 8: {
strcpy(CurrentEntityLayer, CurrentEALItem->resval.rstring);
break;
}
case 10: {
ads_point_set(CurrentEALItem->resval.rpoint, CurrentEntityP1);
break;
}
case 11: {
ads_point_set(CurrentEALItem->resval.rpoint, CurrentEntityP2);
break;
}
case 40: {
CurrentEntitySize1 = CurrentEALItem->resval.rreal;
break;
}
case 41: {
CurrentEntitySize2 = CurrentEALItem->resval.rreal;
break;
}
case 50: {
CurrentEntityStartAng = CurrentEALItem->resval.rreal;
break;
}
case 51: {
CurrentEntityEndAng = CurrentEALItem->resval.rreal;
break;
}
case 62: {
CurrentEntityColor = CurrentEALItem->resval.rint;
break;
}
case 70: {
CurrentEntityFlag = CurrentEALItem->resval.rint;
break;
}
case 75: {
CurrentEntityFit = CurrentEALItem->resval.rint;
break;
}
case 210: {
ads_point_set(CurrentEALItem->resval.rpoint, CurrentEntityEVec);
break;
}
}
CurrentEALItem = CurrentEALItem->rbnext;
}
/* Release the resbuf of the current entity's Association List */
ads_relrb(CurrentEAL);
/* If we don't care about layer or linetype or color, set the
layer or linetype to be matched to a match-anything wild card */
if (CheckLayer == FALSE) {
strcpy(CurrentEntityLayer, "*");
}
if (CheckLType == FALSE) {
strcpy(CurrentEntityLType, "*");
}
if (CheckColor == FALSE) {
MaxColor = 256;
MinColor = 0;
}
else {
MaxColor = MinColor = CurrentEntityColor;
}
/* Start looking for deletion candidates; first separate by the
entity type of the current entity */
/* SECTION TO HANDLE LINES */
if (strcmp(CurrentEntityType, "LINE") == 0) {
/* Skip any lines that are less than 1/1000 of the tolerance
long, since they may be zero length (which will make the
point-to-line distance calculation blow up) and we'll
presume that they will be deleted later when checking some
other line */
if (ads_distance(CurrentEntityP1, CurrentEntityP2) >= (Tolerance/1000.0)) {
/* Set up two points defining diagonally opposite corners of
a brick, P1 being the corner of the brick with the minimum
coordinates and P2 being the corner of the brick with the
maximum coordinates. Any lines that may be
deleted must lie within this brick. */
ads_point_set(CurrentEntityP1, BrickCorner1);
ads_point_set(CurrentEntityP2, BrickCorner2);
for (CoordNum = 0; CoordNum <= 2; CoordNum++) {
if (BrickCorner1[CoordNum] > BrickCorner2[CoordNum]) {
TempReal = BrickCorner1[CoordNum];
BrickCorner1[CoordNum] = BrickCorner2[CoordNum];
BrickCorner2[CoordNum] = TempReal;
}
/* If any side is smaller than twice Tolerance ... */
if (fabs((BrickCorner2[CoordNum] - BrickCorner1[CoordNum])) < 2.0*Tolerance) {
/* Make it equal to twice Tolerance */
TempReal = fabs(BrickCorner2[CoordNum] + BrickCorner1[CoordNum])/2.0;
BrickCorner1[CoordNum] = TempReal - Tolerance;
BrickCorner2[CoordNum] = TempReal + Tolerance;
}
else {
/* Otherwise, increase the side of the brick by a tiny
amount */
TempReal = fabs(BrickCorner2[CoordNum] + BrickCorner1[CoordNum])*Tolerance*0.01;
BrickCorner1[CoordNum] = BrickCorner1[CoordNum] - TempReal;
BrickCorner2[CoordNum] = BrickCorner2[CoordNum] + TempReal;
}
}
/* Get a selection set of all lines lying within the brick
of which the current LINE entity is a diagonal, with
appropriate colors, linetypes, and layers */
SelSetCriteria = ads_buildlist(RTDXF0, "LINE",
-4, ">=,>=,>=",
10, BrickCorner1,
-4, "<=,<=,<=",
10, BrickCorner2,
-4, ">=,>=,>=",
11, BrickCorner1,
-4, "<=,<=,<=",
11, BrickCorner2,
6, CurrentEntityLType,
8, CurrentEntityLayer,
-4, ">=",
62, MinColor,
-4, "<=",
62, MaxColor,
0);
ads_ssget("X", NULL, NULL, SelSetCriteria, DeletionCandidates);
ads_relrb(SelSetCriteria);
/* We got at least one entity, the current one. If there are
other entities ... */
if (ads_sslength(DeletionCandidates, &NumEntsSelected) != RTNORM) {
NumEntsSelected = 0L;
}
if (NumEntsSelected > 1L) {
/* Remove the current entity from the selection set */
ads_ssdel(CurrentEntityName, DeletionCandidates);
NumEntsSelected = --NumEntsSelected;
/* Check each remaining entity */
for (CandidateNumber = 0L; CandidateNumber < NumEntsSelected; CandidateNumber++) {
ads_ssname(DeletionCandidates, CandidateNumber, CandidateName);
CandidateEAL = CandidateEALItem = ads_entget(CandidateName);
/* Extract the pertinent information about the line */
while (CandidateEALItem != NULL) {
switch (CandidateEALItem->restype) {
case 10: {
ads_point_set(CandidateEALItem->resval.rpoint, CandidateP1);
break;
}
case 11: {
ads_point_set(CandidateEALItem->resval.rpoint, CandidateP2);
break;
}
}
CandidateEALItem = CandidateEALItem->rbnext;
}
ads_relrb(CandidateEAL);
/* If neither endpoint of the candidate extends beyond
the current line and both endpoints are close enough
to being on the current line ... */
if (((CurrentDistance = DistancePointToLine(CurrentEntityP1, CurrentEntityP2, CandidateP1)) >= 0.0)
&& (Tolerance > CurrentDistance)
&& ((CurrentDistance = DistancePointToLine(CurrentEntityP1, CurrentEntityP2, CandidateP2)) >= 0.0)
&& (Tolerance > CurrentDistance)) {
/* Delete that entity! */
ads_entdel(CandidateName);
LinesRemoved = ++LinesRemoved;
}
}
}
ads_ssfree(DeletionCandidates);
}
}
/* SECTION TO HANDLE CIRCLES (AND UNDERLYING ARCS) */
else if (strcmp(CurrentEntityType, "CIRCLE") == 0) {
/* First transform the center of the current circle into
the ECS of a circle with an extrusion vector pointing
180 degrees away from the current circle's extrusion vector */
ECSResBuf1.restype = RT3DPOINT;
ECSResBuf1.resval.rpoint[0] = CurrentEntityEVec[0];
ECSResBuf1.resval.rpoint[1] = CurrentEntityEVec[1];
ECSResBuf1.resval.rpoint[2] = CurrentEntityEVec[2];
ECSResBuf2.restype = RT3DPOINT;
ECSResBuf2.resval.rpoint[0] = -CurrentEntityEVec[0];
ECSResBuf2.resval.rpoint[1] = -CurrentEntityEVec[1];
ECSResBuf2.resval.rpoint[2] = -CurrentEntityEVec[2];
ads_trans(CurrentEntityP1, &ECSResBuf1, &ECSResBuf2, 0, TempPoint);
/* Set up two cubes, inside one of which the center of a
duplicate circle or underlying arc must lie. We need
two cubes because circle and arc center coordinates are
in ECS, and a circle or arc with an extrusion vector 180
degrees away from the current entity's extrusion vector
has very different values for coordinates. */
for (CoordNum = 0; CoordNum <= 2; CoordNum++) {
BrickCorner1[CoordNum] = CurrentEntityP1[CoordNum] + Tolerance;
BrickCorner2[CoordNum] = CurrentEntityP1[CoordNum] - Tolerance;
BrickCorner3[CoordNum] = TempPoint[CoordNum] + Tolerance;
BrickCorner4[CoordNum] = TempPoint[CoordNum] - Tolerance;
if (BrickCorner1[CoordNum] > BrickCorner2[CoordNum]) {
TempReal = BrickCorner1[CoordNum];
BrickCorner1[CoordNum] = BrickCorner2[CoordNum];
BrickCorner2[CoordNum] = TempReal;
}
if (BrickCorner3[CoordNum] > BrickCorner4[CoordNum]) {
TempReal = BrickCorner3[CoordNum];
BrickCorner3[CoordNum] = BrickCorner4[CoordNum];
BrickCorner4[CoordNum] = TempReal;
}
}
/* Get a selection set of all circles or arcs with centers
inside either cube, radius within Tolerance of the current
circle's radius, and with appropriate colors, linetypes,
and layers. */
SelSetCriteria = ads_buildlist(-4, "<OR",
RTDXF0, "CIRCLE",
RTDXF0, "ARC",
-4, "OR>",
-4, "<OR",
-4, "<AND",
-4, ">=,>=,>=",
10, BrickCorner1,
-4, "<=,<=,<=",
10, BrickCorner2,
-4, "AND>",
-4, "<AND",
-4, ">=,>=,>=",
10, BrickCorner3,
-4, "<=,<=,<=",
10, BrickCorner4,
-4, "AND>",
-4, "OR>",
-4, ">=",
40, CurrentEntitySize1 - Tolerance,
-4, "<=",
40, CurrentEntitySize1 + Tolerance,
6, CurrentEntityLType,
8, CurrentEntityLayer,
-4, ">=",
62, MinColor,
-4, "<=",
62, MaxColor,
0);
ads_ssget("X", NULL, NULL, SelSetCriteria, DeletionCandidates);
ads_relrb(SelSetCriteria);
/* We got at least one entity, the current one. If there are
other entities ... */
if (ads_sslength(DeletionCandidates, &NumEntsSelected) != RTNORM) {
NumEntsSelected = 0L;
}
if (NumEntsSelected > 1L) {
/* Remove the current entity from the selection set */
ads_ssdel(CurrentEntityName, DeletionCandidates);
NumEntsSelected = --NumEntsSelected;
/* Check each remaining entity */
for (CandidateNumber = 0L; CandidateNumber < NumEntsSelected; CandidateNumber++) {
ads_ssname(DeletionCandidates, CandidateNumber, CandidateName);
CandidateEAL = CandidateEALItem = ads_entget(CandidateName);
/* We know _almost_ enough to delete the candidate entity;
but we're not quite sure the extrusion vectors are
parallel or 180 degrees apart */
/* Extract the extrusion vector and entity type of the
candidate */
while (CandidateEALItem != NULL) {
switch (CandidateEALItem->restype) {
case 0: {
strcpy(CandidateEntityType, CandidateEALItem->resval.rstring);
}
case 210: {
ads_point_set(CandidateEALItem->resval.rpoint, CandidateEVec);
break;
}
}
CandidateEALItem = CandidateEALItem->rbnext;
}
ads_relrb(CandidateEAL);
/* Do the cross product of the two extrusion vectors */
TempPoint[0] = CurrentEntityEVec[1]*CandidateEVec[2]
- CurrentEntityEVec[2]*CandidateEVec[1];
TempPoint[1] = CurrentEntityEVec[2]*CandidateEVec[0]
- CurrentEntityEVec[0]*CandidateEVec[2];
TempPoint[2] = CurrentEntityEVec[0]*CandidateEVec[1]
- CurrentEntityEVec[1]*CandidateEVec[0];
/* Get the magnitude of the cross product, which (for two
unit vectors like extrusion vectors) is the sine of
the angle between them */
TempReal = sqrt(TempPoint[0]*TempPoint[0] +
TempPoint[1]*TempPoint[1] +
TempPoint[2]*TempPoint[2]);
if (TempReal <= Tolerance) {
/* Delete that entity! */
ads_entdel(CandidateName);
if (strcmp(CandidateEntityType, "CIRCLE") == 0) {
CirclesRemoved = ++CirclesRemoved;
}
else {
ArcsRemoved = ++ArcsRemoved;
}
}
}
}
ads_ssfree(DeletionCandidates);
}
/* SECTION TO HANDLE POINTS */
else if (strcmp(CurrentEntityType, "POINT") == 0) {
/* Set up a cube inside which any points to be deleted must lie */
for (CoordNum = 0; CoordNum <= 2; CoordNum++) {
BrickCorner1[CoordNum] = CurrentEntityP1[CoordNum] + Tolerance;
BrickCorner2[CoordNum] = CurrentEntityP1[CoordNum] - Tolerance;
if (BrickCorner1[CoordNum] > BrickCorner2[CoordNum]) {
TempReal = BrickCorner1[CoordNum];
BrickCorner1[CoordNum] = BrickCorner2[CoordNum];
BrickCorner2[CoordNum] = TempReal;
}
}
/* Get a selection set of all points within the cube with
appropriate color, linetype, and layer */
SelSetCriteria = ads_buildlist(RTDXF0, "POINT",
-4, ">=,>=,>=",
10, BrickCorner1,
-4, "<=,<=,<=",
10, BrickCorner2,
6, CurrentEntityLType,
8, CurrentEntityLayer,
-4, ">=",
62, MinColor,
-4, "<=",
62, MaxColor,
0);
ads_ssget("X", NULL, NULL, SelSetCriteria, DeletionCandidates);
ads_relrb(SelSetCriteria);
/* We got at least one entity, the current one. If there are
other entities ... */
if (ads_sslength(DeletionCandidates, &NumEntsSelected) != RTNORM) {
NumEntsSelected = 0L;
}
if (NumEntsSelected > 1L) {
/* Remove the current entity from the selection set */
ads_ssdel(CurrentEntityName, DeletionCandidates);
NumEntsSelected = --NumEntsSelected;
/* Delete all the points */
for (CandidateNumber = 0L; CandidateNumber < NumEntsSelected; CandidateNumber++) {
ads_ssname(DeletionCandidates, CandidateNumber, CandidateName);
ads_entdel(CandidateName);
}
PointsRemoved = PointsRemoved + NumEntsSelected;
}
ads_ssfree(DeletionCandidates);
}
/* SECTION TO HANDLE ARCS */
else if (strcmp(CurrentEntityType, "ARC") == 0) {
/* First transform the center of the current arc into
the ECS of an arc with an extrusion vector pointing
180 degrees away from the current arc's extrusion vector */
ECSResBuf1.restype = RT3DPOINT;
ECSResBuf1.resval.rpoint[0] = CurrentEntityEVec[0];
ECSResBuf1.resval.rpoint[1] = CurrentEntityEVec[1];
ECSResBuf1.resval.rpoint[2] = CurrentEntityEVec[2];
ECSResBuf2.restype = RT3DPOINT;
ECSResBuf2.resval.rpoint[0] = -CurrentEntityEVec[0];
ECSResBuf2.resval.rpoint[1] = -CurrentEntityEVec[1];
ECSResBuf2.resval.rpoint[2] = -CurrentEntityEVec[2];
ads_trans(CurrentEntityP1, &ECSResBuf1, &ECSResBuf2, 0, TempPoint);
/* Set up two cubes, inside one of which the center of a
duplicate or underlying arc must lie. We need
two cubes because arc center coordinates are
in ECS, and an arc with an extrusion vector 180
degrees away from the current entity's extrusion vector
has very different values for coordinates. */
for (CoordNum = 0; CoordNum <= 2; CoordNum++) {
BrickCorner1[CoordNum] = CurrentEntityP1[CoordNum] + Tolerance;
BrickCorner2[CoordNum] = CurrentEntityP1[CoordNum] - Tolerance;
BrickCorner3[CoordNum] = TempPoint[CoordNum] + Tolerance;
BrickCorner4[CoordNum] = TempPoint[CoordNum] - Tolerance;
if (BrickCorner1[CoordNum] > BrickCorner2[CoordNum]) {
TempReal = BrickCorner1[CoordNum];
BrickCorner1[CoordNum] = BrickCorner2[CoordNum];
BrickCorner2[CoordNum] = TempReal;
}
if (BrickCorner3[CoordNum] > BrickCorner4[CoordNum]) {
TempReal = BrickCorner3[CoordNum];
BrickCorner3[CoordNum] = BrickCorner4[CoordNum];
BrickCorner4[CoordNum] = TempReal;
}
}
/* Get a selection set of all arcs with centers
inside either cube, radius within Tolerance of the current
arc's radius, and with appropriate colors, linetypes,
and layers. */
SelSetCriteria = ads_buildlist(RTDXF0, "ARC",
-4, "<OR",
-4, "<AND",
-4, ">=,>=,>=",
10, BrickCorner1,
-4, "<=,<=,<=",
10, BrickCorner2,
-4, "AND>",
-4, "<AND",
-4, ">=,>=,>=",
10, BrickCorner3,
-4, "<=,<=,<=",
10, BrickCorner4,
-4, "AND>",
-4, "OR>",
-4, ">=",
40, CurrentEntitySize1 - Tolerance,
-4, "<=",
40, CurrentEntitySize1 + Tolerance,
6, CurrentEntityLType,
8, CurrentEntityLayer,
-4, ">=",
62, MinColor,
-4, "<=",
62, MaxColor,
0);
ads_ssget("X", NULL, NULL, SelSetCriteria, DeletionCandidates);
ads_relrb(SelSetCriteria);
/* We got at least one entity, the current one. If there are
other entities ... */
if (ads_sslength(DeletionCandidates, &NumEntsSelected) != RTNORM) {
NumEntsSelected = 0L;
}
if (NumEntsSelected > 1L) {
/* Remove the current entity from the selection set */
ads_ssdel(CurrentEntityName, DeletionCandidates);
NumEntsSelected = --NumEntsSelected;
/* Check each remaining entity */
for (CandidateNumber = 0L; CandidateNumber < NumEntsSelected; CandidateNumber++) {
ads_ssname(DeletionCandidates, CandidateNumber, CandidateName);
CandidateEAL = CandidateEALItem = ads_entget(CandidateName);
/* Extract the extrusion vector and start and end angles
of the candidate */
while (CandidateEALItem != NULL) {
switch (CandidateEALItem->restype) {
case 50: {
CandidateStartAng = CandidateEALItem->resval.rreal;
break;
}
case 51: {
CandidateEndAng = CandidateEALItem->resval.rreal;
break;
}
case 210: {
ads_point_set(CandidateEALItem->resval.rpoint, CandidateEVec);
break;
}
}
CandidateEALItem = CandidateEALItem->rbnext;
}
ads_relrb(CandidateEAL);
/* Do the cross product of the two extrusion vectors */
TempPoint[0] = CurrentEntityEVec[1]*CandidateEVec[2]
- CurrentEntityEVec[2]*CandidateEVec[1];
TempPoint[1] = CurrentEntityEVec[2]*CandidateEVec[0]
- CurrentEntityEVec[0]*CandidateEVec[2];
TempPoint[2] = CurrentEntityEVec[0]*CandidateEVec[1]
- CurrentEntityEVec[1]*CandidateEVec[0];
/* Get the magnitude of the cross product, which (for two
unit vectors like extrusion vectors) is the sine of
the angle between them */
TempReal = sqrt(TempPoint[0]*TempPoint[0] +
TempPoint[1]*TempPoint[1] +
TempPoint[2]*TempPoint[2]);
/* Check to make sure the extrusion vectors are
parallel or 180 degrees apart */
if (TempReal <= Tolerance) {
/* Get the start and end angles of the candidate in
the coordinate system of the current entity */
TempStartAng = TransformAngle(CandidateStartAng,
CandidateEVec,
CurrentEntityEVec);
TempEndAng = TransformAngle(CandidateEndAng,
CandidateEVec,
CurrentEntityEVec);
/* If both the start and end angles of the candidate
entity are between the start and end angles of the
current entity ... */
if ((AngleIsBetween(TempStartAng, CurrentEntityStartAng, CurrentEntityEndAng))
&& (AngleIsBetween(TempEndAng, CurrentEntityStartAng, CurrentEntityEndAng))) {
/* Delete that entity! */
ads_entdel(CandidateName);
ArcsRemoved = ++ArcsRemoved;
}
}
}
}
ads_ssfree(DeletionCandidates);
}
/* SECTION TO HANDLE NON-MESH POLYLINES */
else if ((strcmp(CurrentEntityType, "POLYLINE") == 0)
&& (!(16 & CurrentEntityFlag))) {
/* Set up a range of elevations within which any duplicate
polyline must lie */
BrickCorner1[0] = BrickCorner2[0] = BrickCorner1[1] = BrickCorner2[1] = 0.0;
BrickCorner1[2] = CurrentEntityP1[2] + Tolerance;
BrickCorner2[2] = CurrentEntityP1[2] - Tolerance;
if (BrickCorner1[2] > BrickCorner2[2]) {
TempReal = BrickCorner1[2];
BrickCorner1[2] = BrickCorner2[2];
BrickCorner2[2] = TempReal;
}
/* Get a selection set of all polylines within that range of
elevations with appropriate linetype, layer, and color */
SelSetCriteria = ads_buildlist(RTDXF0, "POLYLINE",
-4, ">=,>=,>=",
10, BrickCorner1,
-4, "<=,<=,<=",
10, BrickCorner2,
6, CurrentEntityLType,
8, CurrentEntityLayer,
-4, ">=",
62, MinColor,
-4, "<=",
62, MaxColor,
0);
ads_ssget("X", NULL, NULL, SelSetCriteria, DeletionCandidates);
ads_relrb(SelSetCriteria);
/* We got at least one entity, the current one. If there are
other entities ... */
if (ads_sslength(DeletionCandidates, &NumEntsSelected) != RTNORM) {
NumEntsSelected = 0L;
}
if (NumEntsSelected > 1L) {
/* Remove the current entity from the selection set */
ads_ssdel(CurrentEntityName, DeletionCandidates);
NumEntsSelected = --NumEntsSelected;
/* Check each remaining entity */
for (CandidateNumber = 0L; CandidateNumber < NumEntsSelected; CandidateNumber++) {
ads_ssname(DeletionCandidates, CandidateNumber, CandidateName);
CandidateEAL = CandidateEALItem = ads_entget(CandidateName);
/* Set up defaults for the polyline type flag and fit */
CandidateFlag = CandidateFit = 0;
CandidateEVec[X] = 0.0;
CandidateEVec[Y] = 0.0;
CandidateEVec[Z] = 1.0;
/* Extract the start and end widths, polyline type flag,
curve type of the candidate, and extrusion vector of
the candidate */
while (CandidateEALItem != NULL) {
switch (CandidateEALItem->restype) {
case 40: {
CandidateStartWidth = CandidateEALItem->resval.rreal;
break;
}
case 41: {
CandidateEndWidth = CandidateEALItem->resval.rreal;
break;
}
case 70: {
CandidateFlag = CandidateEALItem->resval.rint;
break;
}
case 75: {
CandidateFit = CandidateEALItem->resval.rint;
break;
}
case 210: {
ads_point_set(CandidateEALItem->resval.rpoint, CandidateEVec);
break;
}
}
CandidateEALItem = CandidateEALItem->rbnext;
}
ads_relrb(CandidateEAL);
/* Make sure that the candidate's start and end widths are
close enough, it's the same type of polyline, the curve
fit type is the same, and the extrusion vector is
pointing close enough to the same direction */
if ((fabs(CandidateStartWidth-CurrentEntitySize1) <= Tolerance)
&& (fabs(CandidateEndWidth-CurrentEntitySize2) <= Tolerance)
&& (CandidateFlag == CurrentEntityFlag)
&& (CandidateFit == CurrentEntityFit)
&& (ads_distance(CurrentEntityEVec, CandidateEVec) <= Tolerance)) {
/* The candidate may not have as many vertices as
the current entity. We have to first
synchronize by sweeping through the vertices of
the current entity looking for one that matches
the first vertex of the candidate */
/* Loop over all vertices of the current entity
until we run out of vertices or synchronize
with the vertices of the candidate. Start
with the first vertex of the candidate, and with
the name of the current entity so we'll get
the first vertex with the first ads_entnext */
ads_name_set(CurrentEntityName, CurrentEntityVertex);
ads_entnext(CandidateName, CandidateVertex);
CandidateVertexData = GetVertexData(CandidateVertex);
Synchronized = ReachedLastVertex = FALSE;
while (!ReachedLastVertex) {
/* Get the next vertex of the current entity */
ads_entnext(CurrentEntityVertex, CurrentEntityVertex);
CurrentEntityVertexData = GetVertexData(CurrentEntityVertex);
/* If we've synchronized with the current entity
already ... */
if (Synchronized) {
/* Get the next vertex of the candidate */
ads_entnext(CandidateVertex, CandidateVertex);
CandidateVertexData = GetVertexData(CandidateVertex);
/* Have we reached the last vertex of the
candidate while still synchronized? */
if (strcmp(CandidateVertexData.Type, "SEQEND") == 0) {
/* Yes, we want to delete the candidate */
ads_entdel(CandidateName);
PlinesRemoved = ++PlinesRemoved;
/* And we're done with this candidate */
ReachedLastVertex = TRUE;
}
else {
/* No, we haven't reached the last vertex of
the candidate. If the candidate's vertex
data and the current entity's vertex data
are not close enough to equal ... */
if (!((ads_distance(CurrentEntityVertexData.Location, CandidateVertexData.Location) <= Tolerance)
&& (fabs(CurrentEntityVertexData.StartWidth-CandidateVertexData.StartWidth) <= Tolerance)
&& (fabs(CurrentEntityVertexData.EndWidth-CandidateVertexData.EndWidth) <= Tolerance)
&& (fabs(CurrentEntityVertexData.Bulge-CandidateVertexData.Bulge) <= Tolerance)
&& (ads_distance(CurrentEntityVertexData.Tangent, CandidateVertexData.Tangent) <= Tolerance)
&& (CurrentEntityVertexData.Flags == CandidateVertexData.Flags))) {
/* Then we've fallen out of
synchronization. Leave the current
entity's vertex as it is and reset
the candidate's vertex to its first
vertex to attempt resynchronization
*/
Synchronized = FALSE;
ads_entnext(CandidateName, CandidateVertex);
CandidateVertexData = GetVertexData(CandidateVertex);
}
}
}
else {
/* No, we haven't yet synchronized the two
polylines. Have we reached the last vertex
of the current entity? */
if (strcmp(CurrentEntityVertexData.Type, "SEQEND") == 0) {
/* Yes, so we can't synchronize these two
entities */
ReachedLastVertex = TRUE;
}
else {
/* No, we haven't run out of vertices on the
current entity; see if we've achieved
synchronization */
if ((ads_distance(CurrentEntityVertexData.Location, CandidateVertexData.Location) <= Tolerance)
&& (fabs(CurrentEntityVertexData.StartWidth-CandidateVertexData.StartWidth) <= Tolerance)
&& (fabs(CurrentEntityVertexData.EndWidth-CandidateVertexData.EndWidth) <= Tolerance)
&& (fabs(CurrentEntityVertexData.Bulge-CandidateVertexData.Bulge) <= Tolerance)
&& (ads_distance(CurrentEntityVertexData.Tangent, CandidateVertexData.Tangent) <= Tolerance)
&& (CurrentEntityVertexData.Flags == CandidateVertexData.Flags)) {
/* We've synchronized! */
Synchronized = TRUE;
}
}
}
}
}
}
}
ads_ssfree(DeletionCandidates);
}
}
/* Report if it's time */
if (((CurrentEntityNumber/ReportIncrement)*ReportIncrement) == CurrentEntityNumber) {
ads_printf("\rExtra Entity Removal %Ld%% done",
(100*CurrentEntityNumber)/NumEntsToCheck);
}
}
/* End our undo group */
ads_command(RTSTR, "._UNDO", RTSTR, "_END", RTNONE);
EndTime = clock();
ads_printf("\rRemoved %Ld line%s, ", LinesRemoved, (LinesRemoved-1 ? "s" : ""));
ads_printf("%Ld circle%s, ", CirclesRemoved, (CirclesRemoved-1 ? "s" : ""));
ads_printf("%Ld arc%s, ", ArcsRemoved, (ArcsRemoved-1 ? "s" : ""));
ads_printf("%Ld polyline%s, ", PlinesRemoved, (PlinesRemoved-1 ? "s" : ""));
ads_printf("and %Ld point%s;", PointsRemoved, (PointsRemoved-1 ? "s" : ""));
TotalRemoved = LinesRemoved + CirclesRemoved + ArcsRemoved + PlinesRemoved + PointsRemoved;
ads_printf("\nTotal %Ld entit%s", TotalRemoved, (TotalRemoved-1 ? "ies" : "y"));
ads_printf(" (%Ld%%) removed in ", (100*TotalRemoved)/NumEntsToCheck);
/* Get the total number of seconds used, and convert it to hours minutes and
seconds */
TotalSeconds = ((float) (EndTime - StartTime))/((float) CLOCKS_PER_SEC);
SecToHMS(TotalSeconds, &ElapsedHours, &ElapsedMinutes, &ElapsedSeconds);
if (ElapsedHours != 0L) {
ads_printf("%Ld hour%s ", ElapsedHours, ElapsedHours-1 ? "s" : "");
}
if (ElapsedMinutes != 0L) {
ads_printf("%Ld minute%s ", ElapsedMinutes, ElapsedMinutes-1 ? "s" : "");
}
ads_printf("%.1f second%s", ElapsedSeconds, ElapsedSeconds-1 ? "s" : "");
/* If we took long enough to calculate a meaningful processing rate,
do so. */
if (TotalSeconds >= 2.0) {
/* Figure out the entities processed per second, and figure
out how many places to show after the decimal point to
have at least (and usually) two significant figures */
EntitiesPerSecond = ((float) NumEntsToCheck)/TotalSeconds;
if ((TempReal = log10(EntitiesPerSecond)) > 0) {
if (TempReal >= 1) {
DecimalPlaces = 0;
}
else {
DecimalPlaces = 1;
}
}
else {
DecimalPlaces = 1 + ceil(-TempReal);
}
/* Print out the result */
if (DecimalPlaces < 8) {
ads_printf(" (%.*f entities processed/second)", DecimalPlaces, EntitiesPerSecond);
}
else {
ads_printf(" (%.1E entities processed/second)", DecimalPlaces, EntitiesPerSecond);
}
}
ads_printf("\n");
/* Redraw the screen so the user sees what's really there */
ads_redraw(NULL, NULL);
}